package com.chzc.goods.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chzc.goods.mapper.GoodsMapper;
import com.chzc.goods.req.GoodsREQ;
import com.chzc.goods.service.IGoodsService;
import com.chzc.goods.service.RedisService;
import com.chzc.po.Goods;
import com.chzc.po.User;
import com.chzc.util.Result;
import com.chzc.util.enums.KillEnum;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author CV大魔王
 * @since 2021-05-27
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {


    @Autowired
    private RedisService redisService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    @Cacheable(value = {"goods"}, key = "#root.methodName+'_'+#req.current+'_'+#req.size+'_'+#req.goodsTitle+'_'+#req.startDate+'_'+#req.endDate")
    public IPage<Goods> queryPageList(GoodsREQ req) {
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(req.getGoodsTitle())) {
            wrapper.like("goods_title", req.getGoodsTitle());
        }
        if (req.getStartDate() != null) {
            wrapper.ge("start_date", req.getStartDate());
        }
        if (req.getEndDate() != null) {
            wrapper.le("end_date", req.getEndDate());
        }
        wrapper.select("id", "goods_title", "goods_img", "goods_content", "goods_price", "seckill_price", "goods_stock", "start_date", "end_date");

        wrapper.eq("status", 1);
        wrapper.orderByDesc("update_time");
        return baseMapper.selectPage(req.getPage(), wrapper);
    }


    @Override
    @CacheEvict(value = "goods", allEntries = true)
    public Result addGoods(Goods goods) {
        goods.setId(null);
        goods.setCreateTime(new Date());
        goods.setUpdateTime(new Date());
        goods.setStatus(1);
        baseMapper.insert(goods);

        // 开始时间压入Redis缓存, 设置过期时间为当前时间-结束时间
        redisService.set(KillEnum.goods_id_start_ + goods.getId(), "0_" + goods.getStartDate().getTime(),
                goods.getEndDate().getTime() - System.currentTimeMillis());

        // 设置该商品最大访问限制为库存加200，超过此现在返回抢购失败，设置过期时间为当前时间-结束时间
        redisService.set(KillEnum.goods_count_ + goods.getId(), goods.getGoodsStock() + 200,
                goods.getEndDate().getTime() - System.currentTimeMillis());
        // 初始化已抢购人数
        redisService.set(KillEnum.goods_access_ + goods.getId(), 0,
                goods.getEndDate().getTime() - System.currentTimeMillis());

        // 初始化商品库存
        redisService.set(KillEnum.goods_stock_ + goods.getId(), goods.getGoodsStock(),
                goods.getEndDate().getTime() - System.currentTimeMillis());
        // 构造Redisson
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(KillEnum.goods_bloom_filter_ + goods.getId());
        // 初始化布隆过滤器：预计元素为商品库存,误差率为3%
        bloomFilter.tryInit(goods.getGoodsStock(), 0.03);

        // 记录商品抢购名次
        redisService.set(KillEnum.goods_ranking_ + goods.getId(),0);

        // 初始化抢购名单
        BoundZSetOperations<String, User> operations = redisTemplate.boundZSetOps(KillEnum.goods_point_rank_real_ + goods.getId());


        return Result.addSuccess(goods);
    }

    @Override
    @CacheEvict(value = "goods", allEntries = true)
    public Result deleteById(String id) {
        Goods goods = baseMapper.selectById(id);
        goods.setStatus(0);
        baseMapper.updateById(goods);

        // 删除商品过期时间限制
        redisService.remove(KillEnum.goods_id_start_ + goods.getId());
        // 删除商品最大访问限制
        redisService.remove(KillEnum.goods_count_ + goods.getId());
        // 删除该商品抢购人数
        redisService.remove(KillEnum.goods_access_ + goods.getId());
        // 删除商品库存内容
        redisService.remove(KillEnum.goods_stock_ + goods.getId());

        // 构造Redisson
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(KillEnum.goods_bloom_filter_ + goods.getId());
        // 初始化布隆过滤器：预计元素为商品库存,误差率为3%
        bloomFilter.tryInit(goods.getGoodsStock(), 0.03);

        return Result.editSuccess();
    }

    @Override
    @CacheEvict(value = "goods", allEntries = true)
    public Result updateGoods(Goods goods) {
        goods.setUpdateTime(new Date());
        baseMapper.updateById(goods);

        // 开始时间压入Redis缓存, 设置过期时间为当前时间-结束时间
        redisService.set(KillEnum.goods_id_start_ + goods.getId(), "0_" + goods.getStartDate().getTime(),
                goods.getEndDate().getTime() - System.currentTimeMillis());

        // 设置该商品最大访问限制为库存加200，超过此现在返回抢购失败，设置过期时间为当前时间-结束时间
        redisService.set(KillEnum.goods_count_ + goods.getId(), goods.getGoodsStock() + 200,
                goods.getEndDate().getTime() - System.currentTimeMillis());
        // 初始化已抢购人数
        redisService.set(KillEnum.goods_access_ + goods.getId(), 0,
                goods.getEndDate().getTime() - System.currentTimeMillis());
        // 初始化商品库存
        redisService.set(KillEnum.goods_stock_ + goods.getId(), goods.getGoodsStock(),
                goods.getEndDate().getTime() - System.currentTimeMillis());

        // 构造Redisson
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(KillEnum.goods_bloom_filter_ + goods.getId());
        // 初始化布隆过滤器：预计元素为商品库存,误差率为3%
        bloomFilter.tryInit(goods.getGoodsStock(), 0.03);

        // 记录商品抢购名次
        redisService.set(KillEnum.goods_ranking_ + goods.getId(),0);

        // 初始化抢购名单
        BoundZSetOperations<String, User> operations = redisTemplate.boundZSetOps(KillEnum.goods_point_rank_real_ + goods.getId());


        return Result.editSuccess(goods);
    }

    @Override
    @Cacheable(value = {"goods"}, keyGenerator = "springCacheDefaultKeyGenerator")
    public Goods findById(String id) {
        return baseMapper.selectById(id);
    }

    @Override
    @Cacheable(value = {"goods"}, keyGenerator = "springCacheDefaultKeyGenerator", cacheManager = "cacheManager10minute")
    public List<Goods> commoditiesOfTheDay() {
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.select("id", "goods_title", "goods_img", "goods_content", "goods_price", "seckill_price", "goods_stock", "start_date", "end_date");
        wrapper.ge("status", 1);
        // 开始时间小于当前时间
        wrapper.le("start_date", new Date());
        // 结束时间大于当前时间
        wrapper.ge("end_date", new Date());
        wrapper.orderByAsc("end_date");
        wrapper.gt("goods_stock", 0);
        return baseMapper.selectList(wrapper);
    }

    @Override
    @Cacheable(value = {"goods"}, keyGenerator = "springCacheDefaultKeyGenerator", cacheManager = "cacheManager10minute")
    public List<Goods> notYetStarted() {
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        wrapper.select("id", "goods_title", "goods_img", "goods_content", "goods_price", "seckill_price", "goods_stock", "start_date", "end_date");
        wrapper.ge("status", 1);
        // 开始时间大于当前时间
        wrapper.ge("start_date", getEndDate());
        // 结束时间大于当前时间
        wrapper.ge("end_date", new Date());
        wrapper.orderByAsc("start_date");
        return baseMapper.selectList(wrapper);
    }


    /**
     * 获取今晚23：59：59
     */
    private Date getEndDate() {
        Date today = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    @Override
    public Integer realTimeInventory(String goodsId) {
        Integer count = (Integer) redisService.get(KillEnum.goods_stock_ + goodsId);
        System.out.println(count);
        return count;
    }
}
